import { InnerCanvas } from './innercanvas';
import { Point, StrokePoint } from '../geometry/point';
import { Stroke } from './stroke';
import { InkSettings } from './inksetting';
import { EventBase } from '../eventbase';
import { EventNames } from './eventnames';

/**
 * 书写处理器
 */
export class InkProcessor extends EventBase {
    /**画板 */
    private _canvas: HTMLCanvasElement;
    /**InnerCanvas实例 */
    private _innerCanvas: InnerCanvas;
    /**鼠标或触控设备最后操作点 */
    private _lastPoint: Point;
    /**最后的线条对象 */
    private _currentStroke: Stroke | null;
    /**鼠标或触控移动处理 */
    private onMouseOrTouchMove = (event: MouseEvent | TouchEvent) => { this.mouseOrTouchMove(event); };
    /**鼠标或触控释放处理 */
    private onMouseOrTouchOut = (event: MouseEvent | TouchEvent) => { this.mouseOrTouchOut(event); };
    /**
     * 构造函数
     * @param innerCanvas 
     * @param canvas 
     */
    constructor(innerCanvas: InnerCanvas, canvas: HTMLCanvasElement) {
        super();
        this._canvas = canvas;
        this._innerCanvas = innerCanvas;
    }
    /**
     * 激活书写处理器
     * @param _event 
     */
    public active(_event: MouseEvent | TouchEvent) {
        let touch: Touch, source: any = null, currentPoint = null;
        if (_event instanceof MouseEvent) {
            source = _event;
        } else if (_event instanceof TouchEvent) {
            source = touch = _event.touches[0];
        }
        currentPoint = new Point(source.clientX, source.clientY);
        currentPoint = this._innerCanvas.clientPointToCanvasPoint(currentPoint);
        this._lastPoint = currentPoint;
        this.attachEvent();
    }
    /**
     * 禁用书写处理器
     * @param _event 
     */
    public deactive(_event: MouseEvent | TouchEvent) {
        this.deattachEvent();
    }
    /**
     * 事件订阅
     */
    private attachEvent() {
        const canvas = this._canvas;
        this.deattachEvent();
        if (canvas) {
            canvas.addEventListener('mousemove', this.onMouseOrTouchMove);
            canvas.addEventListener('mouseup', this.onMouseOrTouchOut);
            canvas.addEventListener('mouseout', this.onMouseOrTouchOut);
            canvas.addEventListener('touchmove', this.onMouseOrTouchMove);
            canvas.addEventListener('touchend', this.onMouseOrTouchOut);
            canvas.addEventListener('touchcancel', this.onMouseOrTouchOut);
        }
    }
    /**
     * 取消事件订阅
     */
    private deattachEvent() {
        const canvas = this._canvas;
        if (canvas) {
            canvas.removeEventListener('mousemove', this.onMouseOrTouchMove);
            canvas.removeEventListener('mouseup', this.onMouseOrTouchOut);
            canvas.removeEventListener('mouseout', this.onMouseOrTouchOut);
            canvas.removeEventListener('touchmove', this.onMouseOrTouchMove);
            canvas.removeEventListener('touchend', this.onMouseOrTouchOut);
            canvas.removeEventListener('touchcancel', this.onMouseOrTouchOut);
        }
    }
    /**
     * 鼠标或触控设备移动处理
     * @param _event 
     */
    private mouseOrTouchMove(_event: MouseEvent | TouchEvent) {
        let touch: Touch | null = null, source: any = null, currentPoint = null;
        if (_event instanceof MouseEvent) {
            source = _event;
        } else if (_event instanceof TouchEvent) {
            source = touch = _event.touches[0];
        }
        // 坐标转换
        currentPoint = new Point(source.clientX, source.clientY);
        currentPoint = this._innerCanvas.clientPointToCanvasPoint(currentPoint);

        // 通知采集到新的点
        try { this.onGesturedPoint(new StrokePoint(currentPoint.x, currentPoint.y), touch); }
        catch (ex) { console.log(ex); }

        // 记录最后操作点
        this._lastPoint = currentPoint;
    }
    /**
     * 鼠标或触控设备移开处理
     * @param _event 
     */
    private mouseOrTouchOut(_event: MouseEvent | TouchEvent) {
        this.deactive(_event);
        this._currentStroke = null;
    }
    /**
     * 采集到新的点处理
     * @param point 
     * @param touch 
     */
    private onGesturedPoint(point: StrokePoint, touch: Touch | null) {
        let isStart = false;
        const lastPoint = new StrokePoint(this._lastPoint.x, this._lastPoint.y);
        // 创建新的线条或加入线条的点
        if (!this._currentStroke) {
            isStart = true;
            const strokeId = InkSettings.createNewStrokeId();
            this._currentStroke = this._innerCanvas.addStroke(strokeId, this._innerCanvas.strokeWidth, this._innerCanvas.strokeColor, [lastPoint, point]);
        } else {
            this._currentStroke.addPoint2(point);
        }

        // 绘制线条
        this._innerCanvas.drawLine(lastPoint, point);

        // 事件通知
        this.publishEvent(EventNames.gesturedPointEventName, {point: point, isStart: isStart, touch: touch});

        // 新线条处理
        if (isStart) {
            this.onNewStroke(this._currentStroke);
        }
    }
    /**
     * 采集到新的线条处理
     * @param stroke 
     */
    private onNewStroke(stroke: Stroke) {
        // 事件通知
        this.publishEvent(EventNames.newStrokeEventName, {stroke: stroke});
    }
}